<script setup lang="ts">
import { inject, nextTick, ref, shallowRef } from 'vue'
import { Message, MessageTransaction, MessageTreeData, SendMessage, TreeMenuItem } from '../../common/types';
import TreeDataTypeSvgVue from '../../components/TreeDataTypeSvg.vue';
import ContextMenuVue from '../../components/ContextMenu.vue';
import { TreeInstance } from 'element-plus/lib/components/index.js';
import Node from "element-plus/lib/components/tree/src/model/node.js";
import helper from '../../common/helpler';
import { MessageTreeDataType, SecsFormat } from '../../common/enums';
import { secsService } from '../../common/api';
import { ElNotification } from 'element-plus';
import { writeText } from '@tauri-apps/plugin-clipboard-manager';


const setCopiedData = inject<(data: MessageTreeData | null, isCut: boolean) => void>("setCopiedData");
const newTransaction = inject<(data: MessageTransaction) => void>("newTransaction");
const props = defineProps<{ maxSize: number }>();
// const props = defineProps<{
//     height: number
// }>()

const messageTree = shallowRef<TreeInstance>();

const defaultProps = {
    children: 'children',
    label: 'label',
    value: "id",
}

const treeData = ref<MessageTreeData[]>([]);
let currentTreeNode: Node | null = null;
const contextMenuRef = shallowRef();

const contextMenuItems: TreeMenuItem[] = [
    {
        label: "Copy",
        isEnable: () => {
            return currentTreeNode?.data.tag.type == MessageTreeDataType.RootValue || currentTreeNode?.data.tag.type == MessageTreeDataType.Value;
        },
        clickHandler: () => {
            if (currentTreeNode == null) {
                return;
            }
            setCopiedData && setCopiedData(helper.duplicateTreeData(currentTreeNode.data as MessageTreeData, false)!, false);
        }
    }, {
        label: "Copy As Text",
        clickHandler: () => {
            if (currentTreeNode == null) {
                return;
            }
            if (currentTreeNode.data.type == MessageTreeDataType.Primary || currentTreeNode.data.type == MessageTreeDataType.Secondary) {
                let message = helper.parseToMessage(currentTreeNode.data as MessageTreeData);
                if (message != null) {
                    secsService.copyMessageText(message);
                }
            }
            else {
                let value = helper.readValue(currentTreeNode.data as MessageTreeData);
                if (value != null) {
                    secsService.copyValueText(value);
                }
            }

        }
    }, {
        label: "Copy Value",
        isEnable: () => {
            return currentTreeNode != null && (currentTreeNode.data.tag.type == MessageTreeDataType.RootValue || currentTreeNode.data.tag.type == MessageTreeDataType.Value) && currentTreeNode.data.tag.format != SecsFormat.List;
        },
        clickHandler: () => {
            if (currentTreeNode == null) {
                return;
            }
            if (currentTreeNode.data.tag.format == SecsFormat.Jis8 || currentTreeNode.data.tag.format == SecsFormat.AscII) {
                if (currentTreeNode.data.tag.value != "") {
                    writeText(currentTreeNode.data.tag.value)
                }
            }
            else if (Array.isArray(currentTreeNode.data.tag.value) && currentTreeNode.data.tag.value.length > 0) {
                writeText(currentTreeNode.data.tag.value.join(" "))
            }
        }
    }, {
        label: "Show Hex (Secs1)",
        isVisible: () => {
            return currentTreeNode?.data.tag.type == MessageTreeDataType.Primary || currentTreeNode?.data.tag.type == MessageTreeDataType.Secondary;
        },
        clickHandler: () => {
            ElNotification({
                title: 'New Feature',
                message: "It hasn't been implemented yet..",
                type: 'info',
            })
        }
    }, {
        label: "-"
    }, {
        label: "Expand",
        isVisible: () => {
            return currentTreeNode?.isLeaf == false;
        },
        clickHandler: () => {
            if (currentTreeNode == null) {
                return;
            }
            helper.expandNode(currentTreeNode, true);
        }
    }, {
        label: "Collapse",
        isVisible: () => {
            return currentTreeNode?.isLeaf == false;
        },
        isEnable: () => {
            return currentTreeNode?.expanded == true;
        },
        clickHandler: () => {
            if (currentTreeNode == null) {
                return;
            }
            currentTreeNode.collapse();
            return true;
        },
    }, {
        label: "Expand All",
        clickHandler: () => {
            for (let i = 0; i < treeData.value.length; i++) {
                const node = messageTree.value?.getNode(treeData.value[i].id);
                if (node != null) {
                    helper.expandNode(node, true);
                }
            }
        }
    }, {
        label: "Collapse All",
        clickHandler: () => {
            for (let i = 0; i < treeData.value.length; i++) {
                const node = messageTree.value?.getNode(treeData.value[i].id);
                if (node != null) {
                    node.collapse();
                }
            }
        }
    }, {
        label: "-"
    }, {
        label: "Delete",
        clickHandler: () => {
            if (currentTreeNode == null) {
                return;
            }
            messageTree.value?.remove(currentTreeNode);
        },
    },
    {
        label: 'Clear',
        clickHandler: () => {
            treeData.value.splice(0);
            return true;
        },
    }, {
        label: "Create As Primary",
        isVisible: () => {
            return import.meta.env.MODE == "development" && (currentTreeNode?.data.tag.type == MessageTreeDataType.Primary || currentTreeNode?.data.tag.type == MessageTreeDataType.Secondary);
        },
        clickHandler: () => {
            if (currentTreeNode == null || (currentTreeNode.data.tag.type != MessageTreeDataType.Primary && currentTreeNode.data.tag.type != MessageTreeDataType.Secondary)) {
                return;
            };
            let message = helper.parseToMessage(currentTreeNode.data as MessageTreeData);
            if (message == null) {
                return;
            }
            message.head.systemByte = 0;
            let transaction: MessageTransaction = {
                id: (++helper.globalId).toString(),
                name: 'S' + message.head.s + 'F' + message.head.f,
                desc: '',
                primary: message,
                secondary: null,
                match_rules: null,
                reply_secondary: false,
                send_primary: null
            };
            if (transaction.primary.head.isExpectReply) {
                transaction.secondary = {
                    name: 'S' + message.head.s + 'F' + (message.head.f + 1),
                    desc: '',
                    head: {
                        s: message.head.s,
                        f: message.head.f + 1,
                        systemByte: 0,
                        isExpectReply: false
                    },
                    body: null,
                }
            }
            newTransaction && newTransaction(transaction);
        }
    }
];

const handleContextMenu = (evt: PointerEvent, _data: MessageTreeData, node: Node) => {
    currentTreeNode = node;
    contextMenuRef.value.show(evt.clientX, evt.clientY);
}

const appendPrimaryMessage = (time: string, message: string) => {
    let messageData = JSON.parse(message) as Message;
    if (messageData.name == null) {
        messageData.name = `S${messageData.head.s}F${messageData.head.f}`;
    }
    let messageTreeData = helper.parseToMessageTreeData(messageData, MessageTreeDataType.Primary, time);
    treeData.value.push(messageTreeData);
    nextTick(() => {
        const node = messageTree.value?.getNode(messageTreeData.id);
        if (node != null) {
            helper.expandNode(node, true);
        }
    });
    if (treeData.value.length > props.maxSize) {
        treeData.value.splice(0, 1);
    }
}

const appendMessage = (message: SendMessage) => {
    if (message.isPrimary) {
        appendPrimaryMessage(message.time, message.message);
    }
    else {
        appendSecondaryMessage(message.time, JSON.parse(message.message));
    }
}

const appendSecondaryMessage = (time: string, message: Message) => {
    if (message.name == null) {
        message.name = `S${message.head.s}F${message.head.f}`;
    }
    let messageTreeData = helper.parseToMessageTreeData(message, MessageTreeDataType.Secondary, time);
    treeData.value.push(messageTreeData);
    nextTick(() => {
        const node = messageTree.value?.getNode(messageTreeData.id);
        if (node != null) {
            helper.expandNode(node, true);
        }
    });
    if (treeData.value.length > props.maxSize) {
        treeData.value.splice(0, 1);
    }
}

const updatePrimaryMessage = (time: string, systemByte: number) => {
    for (let i = 0; i < treeData.value.length; i++) {
        let tag = treeData.value[i].tag;
        if (tag.type == MessageTreeDataType.Primary && tag.systemByte == null) {
            tag.time = time;
            tag.systemByte = systemByte;
            break;
        }
    }
}

const updateSecondaryMessage = (id: string, time: string) => {
    for (let i = treeData.value.length - 1; i >= 0; i--) {
        if (treeData.value[i].id == id) {
            (treeData.value[i].tag as any).time = time;
            break;
        }
    }
}

const onAreaContextMenu = (evt: MouseEvent) => {
    evt.preventDefault();
}

const handleNodeClick = () => {
    contextMenuRef.value.hide();
}

defineExpose({ appendPrimaryMessage, appendSecondaryMessage, updatePrimaryMessage, updateSecondaryMessage, appendMessage });
</script>
<template>
    <div ref="treeContainer" style="width: 100%;" @contextmenu="onAreaContextMenu($event)">
        <el-tree ref="messageTree" class="lib-tree" :data="treeData" :props="defaultProps" :node-key="'id'"
            empty-text="no messages" @node-contextmenu="handleContextMenu" @node-click="handleNodeClick">
            <template #default="{ data }">
                <TreeDataTypeSvgVue :type="data.tag.type" :format="data.tag.format"
                    :length="data.children == null ? 0 : data.children.length"></TreeDataTypeSvgVue>
                <span v-if="data.name != null && data.name.length > 0" style="margin-left:3px">{{ data.name }}</span>
                <span v-if="data.tag.time" style="margin-left:3px;color:#888888">{{ data.tag.time }}</span>
                <span v-if="data.valueString != null && data.valueString != ''" style="margin-left: 3px;"> = {{
                    data.valueString }}</span>
                <span v-if="data.desc != null && data.desc.length > 0"
                    style="margin-left:10px; color:#444444; display: inline;"> {{
                        data.desc
                    }}</span>
                <span v-if="data.tag.isReply === true" style="margin-left:3px">W</span>
                <span v-if="data.tag.systemByte != null" style="margin-left:3px">{{ data.tag.systemByte }}</span>
            </template>
        </el-tree>
        <ContextMenuVue ref="contextMenuRef" :items="contextMenuItems"></ContextMenuVue>
    </div>
</template>